﻿using Microsoft.Extensions.DependencyInjection;
using Serilog;
using System;
using System.Windows;
using WpfIocDemo.Services;

namespace WpfIocDemo;

public partial class App : Application
{
    public App()
    { 
        Services = ConfigureServices();
    }
    //定义一个静态属性保存App的状态
    //Application.Current返回的实际就是App类的实例，所以强转后可以获取Services
    //Application.Current 是一个静态属性，用于获取当前正在运行的 Application 实例
    //WPF应用程序在运行时只有一个Application实例。这个实例是由WPF框架在应用程序启动时自动创建的。
    //new表示定义一个与基类同名的新属性，隐藏基类的属性而不是重写
    //为了能够访问App中定义的额外成员Services，需要将Application.Current强制转换为App类型
    public new static App Current => (App)Application.Current;
    public IServiceProvider Services { get; }
    private static IServiceProvider ConfigureServices()
    {

        //通常认为一个WPF程序就是一个作用域用不到scop，mainwindow可以注册成singleton，其他的view和vm注册transient即可
        // Scop通常用于http，一次请求就是一个作用域，在Asp.Net core中会为http自动创建每一个不同的Scope
        // AddScoped注册服务,scope中是单例,多个不同scope是瞬时,一定要在scope内通过scope.ServiceProvider解析AddScoped服务
        //无论在scope外还是在scope内部,通过services.GetService解析AddScoped注册的服务，都会复用同一个隐式创建的根级Scope
        var services = new ServiceCollection();
        // 注册Serilog，将日志写入文件
        services.AddSingleton<ILogger>(_ =>
        {
            return new LoggerConfiguration().MinimumLevel
                .Debug()
                .WriteTo.File("log.txt")
                .CreateLogger();
        });
        // 服务应该也是单例
        services.AddSingleton<IWebClient, WebClient>();
        services.AddSingleton<ICatFactsService, CatFactsService>();
        services.AddSingleton<IMessageBoxService, MessageBoxService>();
        services.AddTransient<MainWindowViewModel>();
        services.AddTransient<MainWindow>(sp => new MainWindow { DataContext = sp.GetService<MainWindowViewModel>() });
        return services.BuildServiceProvider();
    }
    // 这里是给onStartup事件注册了个方法，也可以采用重载override的方式
    // 没有使用uri的方式启动
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        // GetRequiredService如果服务未注册抛出InvalidOperationException异常。
        // GetService如果服务未注册，返回 null，如果同一接口注册多个，返回最后注册的
        // GetServices 用于获取某个类型的所有注册服务实例（适用于一个类型注册了多个实现的情况）。
        // GetServicesKeyed (.NET 8）根据键获取某个类型的所有注册服务实例
        var mainWindow = Services.GetService<MainWindow>();
        // serviceProvider.GetService(typeof(IMyService));
        // serviceProvider.GetService<IMyService>();
        mainWindow!.Show();
        //下一步，如何单元测试以及Mocking
    }
}
